package websocket.netty.wrjz;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import websocket.netty.ChannelMap;
import websocket.service.ChuanKouService;
import websocket.util.ConfigProperties;
import websocket.util.DigitalTrans;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.Map;


/**
 * 功能描述: netty服务端处理类
 */
@Slf4j
@ChannelHandler.Sharable
public class WrjzNettyServerHandler extends ChannelInboundHandlerAdapter {

    private final Map<String, String> map = new ConfigProperties().getPropertiesMap("application.yml");

    /**
     * 功能描述: 有客户端连接服务器会触发此函数
     *
     * @param ctx 通道
     * @return void
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        int clientPort = insocket.getPort();
        //获取连接通道唯一标识
        ChannelId channelId = ctx.channel().id();
        //如果map中不包含此连接，就保存连接
        if (ChannelMap.getChannelMap().containsKey(channelId)) {
            log.info("客户端:{},是连接状态，连接通道数量:{} ", channelId, ChannelMap.getChannelMap().size());
        } else {
            //保存连接
            ChannelMap.addChannel(channelId, ctx.channel());
            log.info("客户端:{},连接无人机站8093的netty服务器[IP:{}-->PORT:{}]", channelId, clientIp, clientPort);
            log.info("连接通道数量: {}", ChannelMap.getChannelMap().size());
//            ChannelMap.addChannelId(8093, ctx.channel());

        }
        ChannelMap.addChannelId(8093, ctx.channel());

    }

    /**
     * 功能描述: 有客户端终止连接服务器会触发此函数
     *
     * @param ctx 通道处理程序上下文
     * @return void
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        InetSocketAddress inSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = inSocket.getAddress().getHostAddress();
        ChannelId channelId = ctx.channel().id();
        //包含此客户端才去删除
        if (ChannelMap.getChannelMap().containsKey(channelId)) {
            //删除连接
            ChannelMap.getChannelMap().remove(channelId);
            log.info("客户端:{},删除wrj连接 netty服务器[IP:{}-->PORT:{}]", channelId, clientIp, inSocket.getPort());
            log.info("连接通道数量: " + ChannelMap.getChannelMap().size());
//            ChannelMap.removeChannelPort(8093);
        }
    }

    /**
     * 功能描述: 有客户端发消息会触发此函数
     *
     * @param ctx 通道处理程序上下文
     * @param msg 客户端发送的消息
     * @return void
     *
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//        log.info("无人机站8093接收到消息,加载客户端报文,客户端id:{},客户端消息:{} \n",ctx.channel().id(), msg);
        log.info("无人机站8093接收到消息,加载客户端报文,客户端id:{}\n", ctx.channel().id());
//        if (msg instanceof ByteBuf) {
            ByteBuf buf =null;
            try {
                buf = (ByteBuf) msg;
                byte[] bytes = new byte[buf.readableBytes()];
                buf.readBytes(bytes);
                // 使用字节数组进行处理
                String needData = DigitalTrans.printHexString(bytes);
                String wuRenJiZhenTou = map.get("wuRenJiZhenTou");
                ChuanKouService.chuliWuRenJiData(needData, wuRenJiZhenTou);
            }catch (Exception e){//解决了异常数据导致连接中断的问题
                log.info("捕获到数据异常，该条不处理，{}",e.getMessage());
            }
            finally {
                buf.release();
            }
//        }
        //响应客户端
//      this.channelWrite(ctx.channel().id(), msg);
    }


    public void sendMsg(Integer port, ByteBuf msg) throws Exception {
        Channel channel = ChannelMap.getChannePortdMap().get(port);
        if (channel == null) {
            log.info("通道:{},不存在", port);
            return;
        }
        if (msg == null) {
            log.info("服务端响应空的消息");
            return;
        }

        byte[] byteArray = new byte[msg.readableBytes()];
        msg.readBytes(byteArray);
        String message = new String(byteArray, Charset.forName("UTF-8"));

        // 将处理后的数据写回客户端
        ByteBuf out = Unpooled.copiedBuffer(message.getBytes(Charset.forName("UTF-8")));
        //将客户端的信息直接返回写入ctx
        channel.write(out);
        //刷新缓存区
        channel.flush();
    }

    /**
     * 功能描述: 服务端给客户端发送消息
     *
     * @param channelId 连接通道唯一id
     * @param msg       需要发送的消息内容
     */
    public void channelWrite(ChannelId channelId, Object msg) throws Exception {
        Channel channel = ChannelMap.getChannelMap().get(channelId);
        if (channel == null) {
            log.info("通道:{},不存在", channelId);
            return;
        }
        if (msg == null || msg == "") {
            log.info("服务端响应空的消息");
            return;
        }
        //将客户端的信息直接返回写入ctx
        channel.write(msg);
        //刷新缓存区
        channel.flush();
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        String socketString = ctx.channel().remoteAddress().toString();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                log.info("Client:{},READER_IDLE 读超时", socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            } else if (event.state() == IdleState.WRITER_IDLE) {
                log.info("Client:{}, WRITER_IDLE 写超时", socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            } else if (event.state() == IdleState.ALL_IDLE) {
                log.info("Client:{},ALL_IDLE 总超时", socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            }
        }
    }


    /**
     * 功能描述: 发生异常会触发此函数
     *
     * @param ctx   通道处理程序上下文
     * @param cause 异常
     * @return void
     * @Author keLe
     * @Date 2022/8/26
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        log.info("{}:发生了错误,此连接被关闭。此时连通数量:{}", ctx.channel().id(), ChannelMap.getChannelMap().size());
//        log.info("8093:"+cause.getMessage());
    }
}
